package com.cjx.stars.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cjx.stars.common.MyException;
import com.cjx.stars.common.Response;
import com.cjx.stars.common.ResponseUtils;
import com.cjx.stars.mapper.FollowMapper;
import com.cjx.stars.pojo.table.Follow;
import com.cjx.stars.pojo.table.User;
import com.cjx.stars.pojo.vo.UserVo;
import com.cjx.stars.service.FollowService;
import com.cjx.stars.service.UserService;
import com.cjx.stars.utils.UserHolder;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.util.List;

import static com.cjx.stars.constant.FailMessage.*;
import static com.cjx.stars.constant.RedisConstant.USER_FOLLOW_KEY;
import static com.cjx.stars.constant.SystemConstants.PAGE_SIZE;

/**
 * @author cjx
 * @description 针对表【follow】的数据库操作Service实现
 * @createDate 2024-04-12 14:59:38
 */
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow>
        implements FollowService {

    @Resource
    private FollowMapper followMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    @Lazy
    private UserService userService;

    @Override
    public Response<?> followOrUnfollowUser(Long userId) {
        //1.判断该用户是否存在数据库中
        User followUser = userService.getById(userId);
        if (followUser == null) {
            throw new MyException(THE_USER_DOES_NOT_EXIST);
        }
        String loginUser = UserHolder.getUser().getUserId();
        LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getUserId, Long.valueOf(loginUser))
                .eq(Follow::getFollowUserId, userId);
        //2.查询Redis判断登录用户是否关注目标用户
        String key = USER_FOLLOW_KEY + userId;
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, loginUser);
        //关注
        if (BooleanUtil.isTrue(isMember)) {
            //3.删除Redis中的关注信息
            Boolean isDelete = stringRedisTemplate.delete(key);
            if (BooleanUtil.isFalse(isDelete)) {
                throw new MyException(UNFOLLOW_FAILED);
            }
            //4.删除数据库中的关注信息
            boolean isRemove = remove(wrapper);
            if (!isRemove) {
                throw new MyException(UNFOLLOW_FAILED);
            }
        } else {
        //未关注
            //5.增添Redis中的关注信息
            Long isAdd = stringRedisTemplate.opsForSet().add(key, loginUser);
            if (isAdd == null  || isAdd == 0) {
                throw new MyException(FOLLOW_FAILED);
            }
            //6.增添数据库中的关注信息
            Follow follow = new Follow();
            follow.setUserId(Long.valueOf(loginUser));
            follow.setFollowUserId(userId);
            if (!save(follow)) {
                throw new MyException(FOLLOW_FAILED);
            }
        }
        return ResponseUtils.success();
    }

    @Override
    public boolean isFollowTheUser(Long userId) {
        return count(new LambdaQueryWrapper<Follow>()
                .eq(Follow::getUserId, Long.valueOf(UserHolder.getUser().getUserId()))
                .eq(Follow::getFollowUserId, userId)) != 0;
    }

    @Override
    public Response<?> myFollowList(int currentPage) {
        //1.创建查询条件
        String loginUser = UserHolder.getUser().getUserId();
        LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getUserId, Long.valueOf(loginUser));
        //2.调用分页查询方法
        Page<Follow> page = selectFollowPage(currentPage,wrapper);
        //3.判断是否有关注信息
        List<Follow> followList = page.getRecords();
        if (followList == null || followList.isEmpty()){
            return ResponseUtils.success(page);
        }
        //4.查询关注的用户信息
        List<Long> userIdList = followList.stream().map(Follow::getFollowUserId).toList();
        return selectFollowUserPage(page,userIdList,loginUser);
    }

    /**
     * 根据关注信息中的用户Id返回用户信息
     *
     * @param wrapper     查询条件
     * @param currentPage 分页数据
     * @param page
     * @param userIdList
     * @param loginUser   当前登录类
     * @return 返回信息
     */
    private Response<? extends Page> selectFollowUserPage(Page<Follow> page, List<Long> userIdList, String loginUser) {
        List<UserVo> userVoList = userService.getUserListByIdList(userIdList, Long.valueOf(loginUser));
        //5.封装返回信息
        Page pageVo = BeanUtil.copyProperties(page, page.getClass(), "records");
        pageVo.setRecords(userVoList);
        //3.返回结果
        return ResponseUtils.success(pageVo);
    }

    @Override
    public Response<?> myFansList(int currentPage) {
        //1.创建查询条件
        String loginUser = UserHolder.getUser().getUserId();
        LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFollowUserId, Long.valueOf(loginUser));
        //2.调用分页查询方法
        Page<Follow> page = selectFollowPage(currentPage,wrapper);
        //3.判断是否有关注信息
        List<Follow> followList = page.getRecords();
        if (followList == null || followList.isEmpty()){
            return ResponseUtils.success(page);
        }
        //4.查询关注的用户信息
        List<Long> userIdList = followList.stream().map(Follow::getUserId).toList();
        return selectFollowUserPage(page,userIdList,loginUser);
    }

    @Override
    public List<Long> getFollowIds(Long userId) {
        List<Follow> follows = followMapper.selectList(new LambdaQueryWrapper<Follow>().eq(Follow::getFollowUserId, userId));
        return follows.stream().map(Follow::getUserId).toList();
    }

    /**
     * 条件分页查询关注信息
     * @param currentPage 分页数据
     * @param wrapper 查询条件
     * @return 分页数据
     */
    private Page<Follow> selectFollowPage(int currentPage, LambdaQueryWrapper<Follow> wrapper) {
        Page<Follow> selectPage = new Page<>(currentPage, PAGE_SIZE);
        Page<Follow> followPage = followMapper.selectPage(selectPage, wrapper);
        if (followPage == null){
            throw new MyException(QUERY_FAILED);
        }
        return followPage;
    }
}




